package org.example.hrpc.rpc.handler;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;
import org.example.hrpc.common.spi.loader.ExtensionLoader;
import org.example.hrpc.rpc.common.Constant;
import org.example.hrpc.rpc.message.MessageType;
import org.example.hrpc.rpc.message.Request;
import org.example.hrpc.rpc.message.Response;
import org.example.hrpc.rpc.message.SerializationType;
import org.example.hrpc.serializer.Serializer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Objects;

/**
 * 这里不能指定Message类型，因为想想把该类做成一个通用的Encoder
 * magic4B|messageType1B|SerializationType1B|requestId8B|responseStatus1B|length4B|body
 * magic
 */
public class Encoder extends MessageToByteEncoder {
    private static final Logger logger = LoggerFactory.getLogger(Encoder.class);

    public final static Encoder ENCODER = new Encoder();

    @Override
    protected void encode(ChannelHandlerContext channelHandlerContext, Object o, ByteBuf byteBuf) throws Exception {
        if(o instanceof Request) {
            encodeRequest(channelHandlerContext, (Request) o, byteBuf);
            logger.info("Success write Request message: {}", o);
        } else if (o instanceof Response) {
            encodeResponse(channelHandlerContext, (Response) o, byteBuf);
        } else {
            logger.error("Error message type: {}", o);
        }
    }

    /*
    magic4B|messageType1B|SerializationType1B|requestId4B|responseStatus1B|length4B|body
    4+1+1+4+4=14
     */
    private void encodeRequest(ChannelHandlerContext ctx, Request request, ByteBuf byteBuf){
        // magic
        byteBuf.writeBytes(Constant.MAGIC_NUMBER);
        // 消息类型
        byteBuf.writeByte(request.getMessageType().getCode());
        // 序列化类型
        SerializationType serializationType = request.getSerializationType();
        byteBuf.writeByte(serializationType.getCode());
        // 请求ID
        byteBuf.writeLong(request.getRequestId());
        // 响应状态,因为这是request信息，所以置为0
        byteBuf.writeByte((byte)0);
        // 消息长度，消息长度是整个消息的长度
        int length = Constant.TOTAL_LENGTH;
        byte[] data = null;
        // HeartBeat消息的body体为null
        if(MessageType.SERVICE_REQUEST.equals(request.getMessageType())) {
            Serializer serializer = ExtensionLoader.getExtensionLoader(Serializer.class).getExtension(serializationType.getName());
            try {
                data = serializer.serialize(request.getData());
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
            length += data.length;
        }
        byteBuf.writeInt(length);
        // 写入消息体
        if(Objects.nonNull(data)) {
            byteBuf.writeBytes(data);
        }
        logger.info("Write Request message, length: {}, data length: {}", length, data.length);
    }

    private void encodeResponse(ChannelHandlerContext ctx, Response response, ByteBuf byteBuf) {
        byteBuf.writeBytes(Constant.MAGIC_NUMBER);
        byteBuf.writeByte(response.getMessageType().getCode());
        SerializationType serializationType = response.getSerializationType();
        byteBuf.writeByte(serializationType.getCode());
        byteBuf.writeLong(response.getRequestId());
        byteBuf.writeByte(response.getServiceStatus().getCode());
        int length = Constant.TOTAL_LENGTH;
        byte[] data = null;
        if(MessageType.SERVICE_RESPONSE.equals(response.getMessageType())) {
            Serializer serializer = ExtensionLoader.getExtensionLoader(Serializer.class).getExtension(serializationType.getName());
            try {
                data = serializer.serialize(response.getResult());
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
            length += data.length;
        }
        byteBuf.writeInt(length);
        if(Objects.nonNull(data)) {
            byteBuf.writeBytes(data);
        }
        logger.info("Write Response Message, length: {}, data length: {}", length, data.length);
    }
}
